package com.ma.array.binary;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * @ClassName TestAQS
 * @Author: mayongqiang
 * @DATE 2022/3/24 9:39
 * @Description:
 */
public class TestAQS {
    public static void main(String[] args) {
        Mutex lock = new Mutex();

        new PriorityQueue<Integer>(
                (o1, o2) -> {return 0;}
        );

        new Thread(()->{
            lock.lock();
            System.out.println("1");
            lock.lock();
            try {
                System.out.println("t1 ...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        },"t1").start();
        new Thread(()->{
            lock.lock();
            try {
                System.out.println("t2 ...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        },"t2").start();
    }
}

//自定义同步器
/*
    首先，我们需要去继承AbstractQueuedSynchronizer这个类，然后我们根据我们的需求去重写相应的方法，
    比如要实现一个独占锁，那就去重写tryAcquire，tryRelease方法，要实现共享锁，就去重写tryAcquireShared，tryReleaseShared；
    最后，在我们的组件中调用AQS中的模板方法就可以了，而这些模板方法是会调用到我们之前重写的那些方法的。
    也就是说，我们只需要很小的工作量就可以实现自己的同步组件，重写的那些方法，
    仅仅是一些简单的对于共享资源state的获取和释放操作，至于像是获取资源失败，线程需要阻塞之类的操作，自然是AQS帮我们完成了。

    1.使用者继承AbstractQueuedSynchronizer并重写指定的方法。（这些重写方法很简单，无非是对于共享资源state的获取和释放）
　　 2.将AQS组合在自定义同步组件的实现中，并调用其模板方法，而这些模板方法会调用使用者重写的方法。
 */

//自定义互斥锁
class Mutex implements java.io.Serializable {
    //自定义同步器类
    private static class MySync extends AbstractQueuedSynchronizer {
        protected MySync() {
            super();
        }

        //独占式获取同步状态，试着获取，成功返回true，反之为false
        @Override
        protected boolean tryAcquire(int arg) {
            //当状态为0的时候获取锁，CAS操作成功，则state状态为1，
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        ////释放锁，将同步状态置为0
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) throw new IllegalStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        //是否在独占模式下被线程占用
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    }

    //同步对象完成一系列复杂的工作，我们只需要指向它
    private final MySync sync = new MySync();

    //加锁操作，代理到acquire（模板方法）上就行，acquire会调用我们重写的tryAcquire方法
    public void lock() {
        sync.acquire(1);
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    //释放锁，代理到release（模板方法）上就行，release会调用我们重写的tryRelease方法。
    public void unlock() {
        sync.release(1);
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }


}


